using System;
using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.Pool;
using Object = UnityEngine.Object;

namespace Script
{
    public interface IPool
    {
        public void InitPool(string rootName, string prefabName, int poolMaxSize = 10000, int poolCapacity = 20);
        public void OnInitPool();
    }

    public abstract class PoolBase<TO, TP> : IPool where TO : class, IPoolObject, new()
        where TP : PoolBase<TO, TP>, new()
    {
        private string _rootName;
        private Transform _poolRoot = null;
        private Transform _poolObjectRoot = null;

        private ObjectPool<TO> _pool = null;
        private int _poolMaxSize = 10000;
        private int _poolCapacity = 20;
        private string _prefabName;
        private GameObject _prefab;

        public virtual void InitPool(string rootName, string prefabName, int poolMaxSize = 10000, int poolCapacity = 20)
        {
            _poolObjectRoot = GameObject.Find(rootName)?.transform;
            _rootName = rootName;
            _prefabName = prefabName;
            _prefab = ResKit.Instance.GetResByResName<GameObject>("Prefab", prefabName);
            if (_poolObjectRoot == null)
            {
                _poolRoot = GameObject.Find("PoolRoot")?.transform;
                if (_poolRoot == null)
                {
                    var poolRoot = new GameObject("PoolRoot");
                    poolRoot.transform.SetParent(GameBoot.Instance.transform);
                    poolRoot.transform.localPosition = Vector3.zero;
                    _poolRoot = poolRoot.transform;
                }

                var poolObjectRoot = new GameObject(rootName);
                poolObjectRoot.transform.SetParent(_poolRoot);
                poolObjectRoot.transform.localPosition = Vector3.zero;
                _poolObjectRoot = poolObjectRoot.transform;
            }

            _poolMaxSize = poolMaxSize;
            _poolCapacity = poolCapacity;
            OnInitPool();
        }

        public virtual void OnInitPool()
        {
            //unity object pool 的方式 进行初始化 
            _pool = new ObjectPool<TO>(CreatePoolObject, GetPoolObject, ReleasePoolObject, DestroyPoolObject,
                defaultCapacity: _poolCapacity, maxSize: _poolMaxSize);
        }

        protected virtual TO CreatePoolObject()
        {
            if (_prefab == null) Debug.Log("_prefab is null");
            if (_poolObjectRoot == null) Debug.Log("_poolObjectRoot is null");

            var go = Object.Instantiate(_prefab, _poolObjectRoot, true);
            go.transform.localPosition = Vector3.zero;
            TO obj = go.GetComponent<TO>();
            return obj.CreatePoolObject() as TO;
        }

        protected virtual void GetPoolObject(TO obj)
        {
            obj.GetPoolObject();
        }

        protected virtual void ReleasePoolObject(TO obj)
        {
            obj.ReleasePoolObject();
        }

        protected virtual void DestroyPoolObject(TO obj)
        {
            obj.DestroyPoolObject();
        }

        public void SetPoolMaxSizeAndCapacity(int maxSize, int capacity)
        {
            _poolMaxSize = maxSize;
            _poolCapacity = capacity;
            RetSetPool();
        }

        protected virtual void RetSetPool()
        {
            ReleaseAllPoolObjects();
            ClearPoolObject();
            OnInitPool();
        }

        public virtual TO Get()
        {
            return _pool.Get();
        }

        public virtual void Release(TO obj)
        {
            _pool.Release(obj);
        }


        public virtual int GetConutActive()
        {
            return _pool.CountActive;
        }

        public virtual int GetCountInActive()
        {
            return _pool.CountInactive;
        }


        public virtual int GetCountAll()
        {
            return _pool.CountAll;
        }

        public Transform GetPoolObjectRoot()
        {
            return _poolObjectRoot;
        }

        public void ReleaseAllPoolObjects()
        {
            
            var childrenList =_poolObjectRoot.GetComponentsInChildren<TO>();
            foreach (var child in childrenList)
            {
                Release(child);
            }
        }

        public void ClearPoolObject()
        {
            _pool.Clear();
        }

        public void DestroyPool()
        {
            if (_poolObjectRoot != null)
            {
                Type poolType = typeof(TP);
                string poolTypeName = poolType.ToString();
                PoolManager.Instance.RemovePool(poolTypeName);

                ClearPoolObject();

                Object.Destroy(_poolObjectRoot.gameObject);
                _poolObjectRoot = null;
            }
        }

        //统一的注册初始化
        public static void RegisterPool([CanBeNull] TP tp = null ,bool isReset = false)
        {
            Type poolType = typeof(TP);
            string poolTypeName = poolType.ToString();
            string rootName = $"{poolType.Name}Root";


            if (IsContainPool(poolTypeName) && !isReset) return;
            
            TP poolInstance = tp;
            
            if (poolInstance == null)
            {
                poolInstance= new TP();
            }

            string objectTypeName = typeof(TO).Name;

            PoolManager.Instance.RegisterPool(
                poolTypeName,
                poolInstance,
                rootName,
                objectTypeName
            );
        }
        
        //判断是否已经创建了
        public static bool IsContainPool(string poolName)
        {
            return PoolManager.Instance.IsContainPool(poolName);
        }
    }
}